﻿using System;
using System.Reflection;
using System.Data;

namespace EnterpriseFramework.DataAccess
{
    /// <summary>
    /// Represents a property based column.
    /// </summary>
    public class PropertyColumn : AbstractColumn
    {
        PropertyInfo property;
        MethodInfo getter;
        MethodInfo setter;

        public PropertyColumn(PropertyInfo property, string name, DbType dbtype, int size, bool allowNull, bool isComputed,
            bool isReadOnly, bool primaryKey, bool autoIncr, bool isUnique, bool concurrency)
            : base(name, dbtype, size, allowNull, isComputed, isReadOnly, primaryKey, autoIncr, isUnique, concurrency,
            property.Name)
        {
            this.property = property;
            this.getter = property.GetGetMethod(true);
            this.setter = property.GetSetMethod(true);
        }

        /// <summary>
        /// True if this column can be written to. That is,
        /// whether calling the Write method can actually
        /// attempt to write a value into a target object.
        /// </summary>
        public override bool Writeable
        {
            get { return setter != null; }
        }

        /// <summary>
        /// True if this column can be read from. That is,
        /// whether calling the Read method will return a valid value.
        /// </summary>
        public override bool Readable
        {
            get { return getter != null; }
        }

        /// <summary>
        /// Attempts to write a given value info a given target object.
        /// </summary>
        /// <param name="target">target object</param>
        /// <param name="value">value to write</param>
        public override void Write(object target, object value)
        {
            if (!Writeable)
                return;
            setter.Invoke(target, new object[] { value });
        }

        /// <summary>
        /// Attempts to read a value from a given source object.
        /// </summary>
        /// <param name="source">source object</param>
        /// <returns>value of this column from the source object</returns>
        public override object Read(object source)
        {
            if (!Readable)
                return null;
            return getter.Invoke(source, null);
        }
    }
}
